package org.example.hw.model;

import java.util.Date;
import java.util.HashSet;
import java.util.Set;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Past;
import javax.validation.constraints.Size;

import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import org.hibernate.envers.Audited;
import org.hibernate.validator.constraints.Email;
import org.hibernate.validator.constraints.NotBlank;
import org.springframework.format.annotation.DateTimeFormat;

@Entity
@Table(name = "HW_USERS")
@Audited
public class User extends AbstractEntity {

	@NotBlank
	@Size(min = 3, max = 10)
	@Column(nullable = false, unique = true)
	private String username;

	@NotBlank
	@Column(nullable = false)
	private String password;

	private String firstname;

	private String lastname;

	@Email
	@NotBlank
	@Column(nullable = false)
	private String email;

	// TODO: date time format - menjace se u zavisnosti od lokala, kako to uraditi?
	@DateTimeFormat
	@Past
	private Date dateOfBirth;

	@NotNull
	@Column(nullable = false)
	private Boolean active;

	@OneToMany(mappedBy = "createdBy", fetch = FetchType.LAZY)
	private Set<Link> links = new HashSet<Link>();

	public User() {

	}

	public String getUsername() {
		return username;
	}

	public void setUsername(String username) {
		this.username = username;
	}

	public String getFirstname() {
		return firstname;
	}

	public void setFirstname(String firstname) {
		this.firstname = firstname;
	}

	public String getLastname() {
		return lastname;
	}

	public void setLastname(String lastname) {
		this.lastname = lastname;
	}

	public String getPassword() {
		return password;
	}

	public void setPassword(String password) {
		this.password = password;
	}

	public String getEmail() {
		return email;
	}

	public void setEmail(String email) {
		this.email = email;
	}

	public Boolean getActive() {
		return active;
	}

	public void setActive(Boolean active) {
		this.active = active;
	}

	public Date getDateOfBirth() {
		return dateOfBirth;
	}

	public void setDateOfBirth(Date dateOfBirth) {
		this.dateOfBirth = dateOfBirth;
	}

	public Set<Link> getLinks() {
		return links;
	}

	public void setLinks(Set<Link> links) {
		this.links = links;
	}

	@Override
	public int hashCode() {
		return new HashCodeBuilder().
				// appendSuper(super.hashCode()).
				append(username).
				append(firstname).
				append(lastname).
				append(email).
				append(dateOfBirth).
				append(active).
				append(getCreationTime()).
				append(getModificationTime()).
				hashCode();
	}

	@Override
	public boolean equals(Object obj) {
		if (obj == null) {
			return false;
		}
		if (obj == this) {
			return true;
		}
		if (obj.getClass() != getClass()) {
			return false;
		}

		final User otherUser = (User) obj;

		return new EqualsBuilder().
				// appendSuper(super.equals(obj)).
				append(username, otherUser.getUsername()).
				append(firstname, otherUser.getFirstname()).
				append(lastname, otherUser.getLastname()).
				append(email, otherUser.getEmail()).
				append(dateOfBirth, otherUser.getDateOfBirth()).
				append(active, otherUser.getActive()).
				append(getCreationTime(), otherUser.getCreationTime()).
				append(getModificationTime(), otherUser.getModificationTime()).
				isEquals();
	}

	@Override
	public String toString() {
		return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE).
				append("username", username).
				append("firstname", firstname).
				append("lastname", lastname).
				append("email", email).
				append("dateOfBirth", dateOfBirth).
				append("active", active).
				append("creationTime", getCreationTime()).
				append("modificationTime", getModificationTime()).
				toString();
	}

}
